/**
 *	@file	plist.h
 *
 *	@brief	The circle bi-direction list implement, copy from haproxy.
 *	
 *	@author	Forrest.zhang
 *
 *	@date
 */

#ifndef __H_FZ_PLIST_H__
#define __H_FZ_PLIST_H__

typedef struct plist {
	struct plist	*p;	/* previous element */
	struct plist	*n;	/* next element */
} plist_t;

typedef struct plist_head_t {
	struct plist 	*p;	/* must be same as plist->p */
	struct plist 	*n;	/* must be same as plist->n*/
	int 		cnt;
} plist_head_t;

#define	PLIST_HINIT(h)		({(h)->p = (h)->n =((plist_t *)(h)); (h)->cnt = 0;})
#define	PLIST_IS_HEMPTY(h)	((h)->cnt == 0)
#define PLIST_HLEN(h)		((h)->cnt)

#define	PLIST_EINIT(l)		((l)->p = (l)->n = (l))
#define	PLIST_ELEM(l, t, m)	((t)(((void *)(l)) - ((void *)&((t)0)->m)))
#define	PLIST_IS_UNLINK(l)	((l)->n == (l))

/* get first element in list */
#define	PLIST_GET_HEAD(lh, t, m)			\
	((lh)->n == ((plist_t *)(lh)) ? NULL : PLIST_ELEM((lh)->n, t, m))
/* get last element in list */
#define	PLIST_GET_TAIL(lh, t, m)			\
	(((lh)->p == ((plist_t *)(lh))) ? NULL : PLIST_ELEM((lh)->p, t, m))

#define	PLIST_ADD_HEAD(lh, l)				\
	({						\
	 	(l)->n = (lh)->n;			\
	 	(l)->p = ((plist_t *)(lh));				\
	 	(l)->n->p = (lh)->n = (l);		\
	 	(lh)->cnt++;				\
	})

#define	PLIST_ADD_TAIL(lh, l)				\
	({						\
	 	(l)->p = (lh)->p;			\
	 	(l)->n = ((plist_t *)(lh));				\
	 	(l)->p->n = (lh)->p = (l);		\
	 	(lh)->cnt++;				\
	})

#define	PLIST_INSERT(lh, l, pos)				\
	({						\
	 	(l)->n->p = (pos);			\
	 	(pos)->n = (l)->n;			\
	 	(l)->n = (pos);			\
	 	(pos)->p = (l);			\
	 	(lh)->cnt++;				\
	})


#define	PLIST_DEL(lh, l)					\
	({ 						\
	 	(l)->n->p = (l)->p;			\
	 	(l)->p->n = (l)->n;			\
	 	PLIST_EINIT(l);				\
	 	(lh)->cnt--;				\
	 })

#define	PLIST_FOR_EACH(lh, e, m)			\
	for (e = PLIST_ELEM((lh)->n, typeof(e), m);	\
	     &e->m != ((plist_t *)(lh));				\
	     e = PLIST_ELEM(e->m.n, typeof(e), m)) 

#define	PLIST_FOR_EACH_SAFE(lh, e, b, m)		\
	for (e = PLIST_ELEM((lh)->n, typeof(e), m),	\
	     b = PLIST_ELEM(e->m.n, typeof(e), m);	\
	     &e->m != ((plist_t *)(lh));				\
	     e = b, b = PLIST_ELEM(b->m.n, typeof(b), m))

#define PLIST_JOIN(lh1, lh2)				\
	({						\
	 	if (!PLIST_IS_HEMPTY((lh2))) 		\
		{					\
	 		(lh1)->p->n = (lh2)->n;		\
	 		(lh2)->n->p = (lh1)->p;		\
	 		(lh1)->p = (lh2)->p;		\
	 		(lh2)->p->n = ((plist_t *)(lh1));		\
	 		(lh1)->cnt += (lh2)->cnt;		\
	 		PLIST_HINIT((lh2));		\
	 	}					\
	 })

#define PLIST_JOIN_HEAD(lh1, lh2)				\
	({						\
	 	if (!PLIST_IS_HEMPTY((lh2))) 		\
		{					\
	 		(lh1)->n->p = (lh2)->p;		\
	 		(lh2)->p->n = (lh1)->n;		\
	 		(lh1)->n = (lh2)->n;		\
	 		(lh2)->n->p = ((plist_t *)(lh1));		\
	 		(lh1)->cnt += (lh2)->cnt;		\
	 		PLIST_HINIT((lh2));		\
	 	}					\
	 })


#endif /* end of FZ_PLIST_H  */


